package common;

import java.awt.*;
import java.awt.geom.*;

import math.geom2d.conic.Circle2D;

/**
 * A circular node that is filled with a color.
 */
public class CircleNode implements Node {
	
	private double x;
	private double y;
	private double size;
	private Color color;
	private static final int DEFAULT_SIZE = 20;
	private String description;
	
	public int ID;
	
	/**
	 * Construct a circle node with a given size and color.
	 * 
	 * @param size
	 *            the size
	 * @param aColor
	 *            the fill color
	 */
	public CircleNode(Color aColor) {
		size = DEFAULT_SIZE;
		x = 0;
		y = 0;
		color = aColor;
		description = "";
	}
	
	public CircleNode(Color aColor, int aSize) {
		size = aSize;
		x = 0;
		y = 0;
		color = aColor;
		description = "";
	}

	public void setColor(Color aColor) {
		color = aColor;
	}

	public Color getColor() {
		return color;
	}
	
	public void setID(int id) {
		ID = id;
	}

	public int getID() {
		return ID;
	}	
	
	public double getX(){
		return x;
	}
	
	public double getY(){
		return y;
	}
	
	public void setSize(double s){
		size = s;
	}
	
	public double getSize(){
		return size;
	}
	
	public void setDescription(String s){
		description = s;
	}
	
	public String getDescription(){
		return description;
	}

	
	public Object clone() {
		try {
			return super.clone();
		} catch (CloneNotSupportedException exception) {
			return null;
		}
	}

	public void draw(Graphics2D g2) {
		Ellipse2D circle = new Ellipse2D.Double(x, y, size, size);
		Color oldColor = g2.getColor();
		g2.setColor(color);
		g2.fill(circle);
		g2.setColor(oldColor);
		g2.draw(circle);
	}

	public void translate(double dx, double dy) {
		x += dx;
		y += dy;
	}

	public boolean contains(Point2D p) {
		Ellipse2D circle = new Ellipse2D.Double(x, y, size, size);
		return circle.contains(p);
	}

	public Rectangle2D getBounds() {
		return new Rectangle2D.Double(x, y, size, size);
	}

	public Point2D getConnectionPoint(Point2D other) {
		double centerX = x + size / 2;
		double centerY = y + size / 2;
		double dx = other.getX() - centerX;
		double dy = other.getY() - centerY;
		double distance = Math.sqrt(dx * dx + dy * dy);
		if (distance == 0)
			return other;
		else
			return new Point2D.Double(centerX + dx * (size / 2) / distance,
					centerY + dy * (size / 2) / distance);
	}
	
	public Point2D getArcConnectionPoint(Point2D other, double radius, boolean side) {
		Point2D nodeCenter = new Point2D.Double(x + size/2, y + size/2);
		Point2D mid = new Point2D.Double((nodeCenter.getX() + other.getX())/2, (nodeCenter.getY() + other.getY())/2);
	    double midDist = other.distance(mid);
		
	    double alpha = Math.acos(midDist/radius);
	    double h = Math.sin(alpha) * radius;
	    
	    double beta = Math.atan2(other.getY()-nodeCenter.getY(), other.getX()-nodeCenter.getX()) - Math.PI/2;
	    double dx = Math.cos(beta) * h;
	    double dy = Math.sin(beta) * h;
	    
	    Point2D center = side?new Point2D.Double(mid.getX() + dx, mid.getY() + dy):new Point2D.Double(mid.getX() - dx, mid.getY() - dy);
	    Circle2D arc = new Circle2D(center.getX(), center.getY(), radius);
	    Circle2D node = new Circle2D(nodeCenter.getX(), nodeCenter.getY(), size/2);
	    math.geom2d.Point2D[] points = new math.geom2d.Point2D[2];
	    Circle2D.getIntersections(arc, node).toArray(points);
	    if (points.length == 2){
	    	int sideInd = side?-1:1;
	    	
	    	Point2D p1 = new Point2D.Double(points[0].getX(), points[0].getY());
	    	Point2D p2 = new Point2D.Double(points[1].getX(), points[1].getY());
	    	
	    	if (new Line2D.Double(nodeCenter, other).relativeCCW(p1) == sideInd) return p1;
	    	else return p2;
	    } else {
	    	return new Point2D.Double(points[0].getX(), points[0].getY());
	    }
	  
	}
}
